import compose from './compose'

/**
 *
 * 创建一个将中间件应用于调度方法的商店增强器Redux商店。 这对于各种任务很方便，例如表达以
 * 简洁的方式进行异步操作，或记录每个操作有效负载。
 *
 * 请参阅`redux-thunk`包作为Redux中间件的示例。
 *
 * 因为中间件可能是异步的，所以这应该是第一个在组合链中存储增强器。
 *
 * 请注意，每个中间件都将被赋予`dispatch`和`getState`函数作为命名参数。
 *
 * @param middlewares 遵循 Redux middleware API 的函数。每个 middleware
 * 接受 Store 的 dispatch 和 getState 函数作为命名参数，并返回一个函数。该函数会被传入
 * 被称为 next 的下一个 middleware 的 dispatch 方法，并返回一个接收 action 的新函数，
 * 这个函数可以直接调用 next(action)，或者在其他需要的时刻调用，甚至根本不去调用它。调用链
 * 中最后一个 middleware 会接受真实的 store 的 dispatch 方法作为 next 参数，并借此结束
 * 调用链。所以，middleware 的函数签名是 ({ getState, dispatch }) => next => action。
 *
 * @returns {function(*): function(*=, *=, *=)} 一个应用了 middleware 后的 store
 * enhancer。这个 store enhancer 的签名是 createStore => createStore，但是最简单的
 * 使用方法就是直接作为最后一个 enhancer 参数传递给 createStore() 函数。
 */
export default function applyMiddleware(...middlewares) {
  // 这里执行 createStore 函数，把 applyMiddleware 函数最后次调用的参数传进来）
  return (createStore) => (reducer, preloadedState, enhancer) => {
    // 获取createStore初始化的store
    const store = createStore(reducer, preloadedState, enhancer)
    // 获取初始化的dispath函数
    let dispatch = store.dispatch
    // 数组链
    let chain = []

    // 给中间传递store中的API
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    // 为 middleware 分配统一的 middlewareAPI 后，
    // 将 middleware 返回的函数（这里称作 handler）收集在 chain 数组中
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 和之前一样，从右至左调用每个中间件，然后传入 store.dispatch
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch //middleware handler 处理后的 dispatch
    }
  }
}
